package com.qingcloud.adminbackend.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qingcloud.adminbackend.entity.message.*;
import com.qingcloud.adminbackend.mapper.message.*;
import com.qingcloud.adminbackend.entity.message.*;
import com.qingcloud.adminbackend.enums.EventOriginEnum;
import com.qingcloud.adminbackend.enums.MessageConfigEnum;
import com.qingcloud.adminbackend.enums.TriggerTypeEnum;
import com.qingcloud.adminbackend.mapper.message.*;
import com.qingcloud.adminbackend.pojo.OptionNode;
import com.qingcloud.adminbackend.service.ISysMessageService;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 平台消息事件 服务实现类
 * </p>
 *
 * @author zhoujun
 * @since 2021-11-24
 */
@Service
public class SysMessageServiceImpl implements ISysMessageService {

    @Resource
    private SysMessageConfigMapper sysMessageConfigMapper;

    @Resource
    private SysMessageTypeConfigMapper sysMessageTypeConfigMapper;

    @Resource
    private SysMessageEventMapper sysMessageEventMapper;

    @Resource
    private SysMessageNotifyMapper sysMessageNotifyMapper;

    @Resource
    private SysMessageTypeFieldMapper messageTypeFieldMapper;

    @Resource
    private SysMessageEventSaveRuleMapper saveRuleMapper;

    @Resource
    private SysMessageEventCalRuleMapper calRuleMapper;

    @Resource
    private SysMessageEventCalCompareMapper calCompareMapper;

    @Override
    @Transactional
    public int saveMessageConfig(SysMessageConfig config) {
        if (null != config.getId()) {
            QueryWrapper<SysMessageConfig> configQueryWrapper = new QueryWrapper<>();
            configQueryWrapper.eq("id", config.getId());
            SysMessageConfig messageConfig = sysMessageConfigMapper.selectOne(configQueryWrapper);
            if (messageConfig == null) {
                return -1;
            }
            sysMessageConfigMapper.update(config, configQueryWrapper);
        } else {
            sysMessageConfigMapper.insert(config);
        }
        return 1;
    }

    @Override
    public IPage<SysMessageConfig> findConfigList(String type, Integer page, Integer length) {
        Page<SysMessageConfig> sysMessageConfigPage = new Page<>(page, length);
        IPage<SysMessageConfig> sysMessageConfigIPage = sysMessageConfigMapper.findConfigList(sysMessageConfigPage, type);
        List<SysMessageConfig> sysMessageConfigList = new ArrayList<>();
        for (SysMessageConfig messageConfig : sysMessageConfigIPage.getRecords()) {
            messageConfig.setNoticeType(MessageConfigEnum.getNameByCode(messageConfig.getNoticeType()));
            sysMessageConfigList.add(messageConfig);
        }
        sysMessageConfigIPage.setRecords(sysMessageConfigList);
        return sysMessageConfigIPage;
    }

    @Override
    public SysMessageConfig configDetails(Integer id) {
        QueryWrapper<SysMessageConfig> configQueryWrapper = new QueryWrapper<>();
        configQueryWrapper.eq("id", id);
        return sysMessageConfigMapper.selectOne(configQueryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public int savEventType(SysMessageTypeConfig typeConfig) {
        if (null != typeConfig.getId()) {
            QueryWrapper<SysMessageTypeConfig> configQueryWrapper = new QueryWrapper<>();
            configQueryWrapper.eq("id", typeConfig.getId());
            SysMessageTypeConfig sysMessageTypeConfig = sysMessageTypeConfigMapper.selectOne(configQueryWrapper);
            if (sysMessageTypeConfig == null) {
                return -1;
            }
            sysMessageTypeConfigMapper.update(typeConfig, configQueryWrapper);
            //删除旧字段
            messageTypeFieldMapper.delete(
                    Wrappers.<SysMessageTypeField>lambdaQuery().eq(SysMessageTypeField::getTypeId, typeConfig.getId())
            );
        } else {
            sysMessageTypeConfigMapper.insert(typeConfig);
        }
        //保存属性字段
        saveTypeField(typeConfig.getId(), typeConfig.getFieldList());
        return 1;
    }

    /**
     * 保存事件类型属性字段
     */
    private void saveTypeField(int typeId, List<SysMessageTypeField> typeFieldList) {
        if (CollUtil.isNotEmpty(typeFieldList)) {
            for (SysMessageTypeField it : typeFieldList) {
                it.setTypeId(typeId);
                messageTypeFieldMapper.insert(it);
                //递归保存字节点
                saveTypeField(typeId, it.getChildren());
            }
        }
    }

    @Override
    public IPage<SysMessageTypeConfig> findEventTypeConfigList(String name, Integer page, Integer length) {
        Page<SysMessageTypeConfig> sysMessageTypeConfigPage = new Page<>(page, length);
        IPage<SysMessageTypeConfig> sysMessageConfigIPage = sysMessageTypeConfigMapper.findConfigList(sysMessageTypeConfigPage, name);
        return sysMessageConfigIPage;
    }

    @Override
    public List<SysMessageTypeConfig> eventTypeList() {
        QueryWrapper<SysMessageTypeConfig> configQueryWrapper = new QueryWrapper<>();
        configQueryWrapper.eq("delete_flag", 0);
        return sysMessageTypeConfigMapper.selectList(configQueryWrapper);
    }

    @Override
    public SysMessageTypeConfig typeConfig(Integer id) {
        QueryWrapper<SysMessageTypeConfig> configQueryWrapper = new QueryWrapper<>();
        configQueryWrapper.eq("id", id);
        final SysMessageTypeConfig typeConfig = sysMessageTypeConfigMapper.selectOne(configQueryWrapper);
        //查询类型字段
        final List<SysMessageTypeField> fieldList = messageTypeFieldMapper.selectList(Wrappers.<SysMessageTypeField>lambdaQuery()
                .eq(SysMessageTypeField::getTypeId, typeConfig.getId()));
        //转树结构
        List<SysMessageTypeField> oneList = fieldList.stream().filter(it -> StrUtil.isBlank(it.getParentId())).collect(Collectors.toList());
        List<SysMessageTypeField> children = fieldList.stream().filter(it -> StrUtil.isNotBlank(it.getParentId())).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(children)) {
            final Map<String, List<SysMessageTypeField>> childrenMap = children.stream().collect(Collectors.groupingBy(SysMessageTypeField::getParentId));
            for (SysMessageTypeField it : fieldList) {
                it.setChildren(childrenMap.getOrDefault(it.getNodeId(), new ArrayList<>()));
            }
        }
        typeConfig.setFieldList(oneList);
        return typeConfig;
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public int saveEvenManage(SysMessageEventVo vo) {
        SysMessageEvent sysMessageEvent = new SysMessageEvent();
        BeanUtil.copyProperties(vo, sysMessageEvent);
        int info = 0;
        if (null != sysMessageEvent.getId()) {
            QueryWrapper<SysMessageEvent> messageEventQueryWrapper = new QueryWrapper<>();
            messageEventQueryWrapper.eq("id", sysMessageEvent.getId());
            SysMessageEvent messageEvent = sysMessageEventMapper.selectOne(messageEventQueryWrapper);
            if (messageEvent == null) {
                return -1;
            }
            sysMessageEvent.setEventCode("E" + (1000 + sysMessageEvent.getId()));
            info = sysMessageEventMapper.update(sysMessageEvent, messageEventQueryWrapper);
        } else {
            info = sysMessageEventMapper.insert(sysMessageEvent);
            sysMessageEvent.setEventCode("E" + (1000 + sysMessageEvent.getId()));
            sysMessageEventMapper.updateById(sysMessageEvent);
        }
        if (info == 1 && null != vo.getSysMessageNotifies() && vo.getSysMessageNotifies().size() > 0) {
            //去除下，重复的通知人
            List<SysMessageNotify> sysMessageNotifyList = vo.getSysMessageNotifies().stream()
                    .collect(Collectors.collectingAndThen(Collectors.toCollection(() ->
                                    new TreeSet<>(Comparator.comparing(o -> o.getConfigId() + ";" + o.getReceiver()))),
                            ArrayList::new));
            //修改时删除原有的通知方式，然后重新插入
            if (vo.getId() != null) {
                QueryWrapper<SysMessageNotify> messageNotifyQueryWrapper = new QueryWrapper<>();
                messageNotifyQueryWrapper.eq("event_id", sysMessageEvent.getId());
                sysMessageNotifyMapper.delete(messageNotifyQueryWrapper);
            }
            for (SysMessageNotify notify : sysMessageNotifyList) {
                notify.setEventId(sysMessageEvent.getId());
                if (StringUtils.isBlank(notify.getReceiver())) {
                    return -2;
                }
                notify.setCreateDt(LocalDateTime.now());
            }
            sysMessageNotifyMapper.insertMessageNotifys(sysMessageNotifyList);
        }
        return 1;
    }

    @Override
    @Transactional
    public int updataEvenManageStatus(List<SysMessageEvent> voList) {
        for (SysMessageEvent vo : voList) {
            QueryWrapper<SysMessageEvent> messageEventQueryWrapper = new QueryWrapper<>();
            messageEventQueryWrapper.eq("id", vo.getId());
            SysMessageEvent messageEvent = sysMessageEventMapper.selectOne(messageEventQueryWrapper);
            if (messageEvent == null) {
                return -1;
            }
            sysMessageEventMapper.update(vo, messageEventQueryWrapper);
        }
        return 1;
    }


    @Override
    public IPage<SysMessageEventListVo> findMessageEventList(SysMessageEventDto dto) {
        Page<SysMessageEventListVo> sysMessageEventPage = new Page<>(dto.getCurrentPage(), dto.getPerPage());
        IPage<SysMessageEventListVo> sysMessageEventIPage = sysMessageEventMapper.findMessageEventList(sysMessageEventPage, dto);
        for (SysMessageEventListVo vo : sysMessageEventIPage.getRecords()) {
            vo.setTriggerTypeName(TriggerTypeEnum.getNameByCode(vo.getTriggerType()));
            if (null != vo.getNotifys()) {
                List<String> str = Arrays.asList(vo.getNotifys().split(","));
                str = str.stream().distinct().collect(Collectors.toList());
                StringBuffer stringBuffer = new StringBuffer();
                str.stream().forEach(f ->
                        stringBuffer.append(MessageConfigEnum.getNameByCode(f)).append(",")
                );
                vo.setNotifys(stringBuffer.deleteCharAt(stringBuffer.length() - 1).toString());
            }
            vo.setEventOriginName(EventOriginEnum.getNameByCode(vo.getEventOrigin()));
        }
        return sysMessageEventIPage;
    }

    @Override
    public SysMessageEventListVo messageEventDetails(Integer id) {
        SysMessageEventDto dto = new SysMessageEventDto();
        dto.setId(id);
        SysMessageEventListVo messageEventListVo = sysMessageEventMapper.findMessageEventById(dto);
        if (null == messageEventListVo) {
            return null;
        }
        if (null != messageEventListVo.getNotifyIds()) {
            List<String> str = Arrays.asList(messageEventListVo.getNotifyIds().split(","));
            str = str.stream().distinct().collect(Collectors.toList());
            messageEventListVo.setNotifyListIds(str);
        }
        List<SysMessageNotify> notifyList = sysMessageNotifyMapper.findMessageEventById(messageEventListVo.getId());
        Map<String, List<SysMessageNotify>> notifyMap = notifyList.stream().collect(Collectors.groupingBy(SysMessageNotify::getNoticeType));
        messageEventListVo.setSysMessageNotifies(notifyMap);

        return messageEventListVo;
    }

    @Override
    @Transactional
    public int deleteMessageEventList(List<Integer> ids) {
        QueryWrapper<SysMessageEvent> sysMessageEventQueryWrapper = new QueryWrapper<>();
        sysMessageEventQueryWrapper.in("id", ids);
        sysMessageEventMapper.delete(sysMessageEventQueryWrapper);
        //删除事件配置的通知方式。
        QueryWrapper<SysMessageNotify> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("event_id", ids);
        return sysMessageNotifyMapper.delete(queryWrapper);
    }

    @Override
    public int deleteMessageEventType(List<Integer> ids) {
        QueryWrapper<SysMessageTypeConfig> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("id", ids);
        SysMessageTypeConfig config = new SysMessageTypeConfig();
        config.setDeleteFlag(1);
        QueryWrapper<SysMessageEvent> sysMessageEventQueryWrapper = new QueryWrapper<>();
        sysMessageEventQueryWrapper.in("type_id", ids);
        List<SysMessageEvent> sysMessageEventList = sysMessageEventMapper.selectList(sysMessageEventQueryWrapper);
        if (sysMessageEventList.size() > 0) {
            return -1;
        }
        return sysMessageTypeConfigMapper.update(config, queryWrapper);
    }

    @Override
    public int deleteMessageConfig(List<Integer> ids) {
        QueryWrapper<SysMessageConfig> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("id", ids);
        SysMessageConfig config = new SysMessageConfig();
        config.setDeleteFlag(1);
        return sysMessageConfigMapper.update(config, queryWrapper);
    }

    /**
     * 事件通知配置查询
     *
     * @return 事件列表
     */
    @Override
    public List<EventMessageInfoVO> eventNoticeConfigList() {
        List<EventMessageInfoVO> resultList = new ArrayList<>();
        List<EventMessageInfoBO> eventMessageInfoList = sysMessageEventMapper.eventNoticeConfigList();
        if (CollUtil.isNotEmpty(eventMessageInfoList)) {
            for (EventMessageInfoBO eventMessageInfoBO : eventMessageInfoList) {
                EventMessageInfoVO eventMessageInfoVO = new EventMessageInfoVO();
                eventMessageInfoVO.setEventName(eventMessageInfoBO.getEventName());
                eventMessageInfoVO.setEventTemplate(eventMessageInfoBO.getEventTemplate());
                List<NoticeConfigBO> noticeConfigList = eventMessageInfoBO.getNoticeConfigList();
                //构建通知配置VO集合
                List<NoticeConfigVO> noticeConfigVOList = buildNoticeConfigVOList(noticeConfigList);
                eventMessageInfoVO.setNoticeConfigList(noticeConfigVOList);
                resultList.add(eventMessageInfoVO);
            }
        }
        return resultList;
    }

    /**
     * 构建通知配置VO集合
     *
     * @param noticeConfigList 通知配置VO
     * @return 通知配置VO集合
     */
    private List<NoticeConfigVO> buildNoticeConfigVOList(List<NoticeConfigBO> noticeConfigList) {
        Map<String, NoticeConfigVO> keyMap = new HashMap<>();
        if (CollUtil.isNotEmpty(noticeConfigList)) {
            for (NoticeConfigBO noticeConfigBO : noticeConfigList) {
                String noticeType = noticeConfigBO.getNoticeType();
                NoticeConfigVO noticeConfigVO = keyMap.get(noticeType);
                Set<String> recipientSet;
                if (noticeConfigVO == null) {
                    noticeConfigVO = new NoticeConfigVO();
                    noticeConfigVO.setNoticeConfig(noticeConfigBO.getNoticeConfig());
                    noticeConfigVO.setNoticeType(noticeType);
                    recipientSet = new HashSet<>();
                } else {
                    recipientSet = noticeConfigVO.getRecipientSet();
                }
                //电子邮件
                if (MessageConfigEnum.MAIL.getType().equals(noticeType)) {
                    String receiver = noticeConfigBO.getReceiver();
                    if (receiver.contains("@")) {
                        recipientSet.add(receiver);
                    } else {
                        String workEmail = noticeConfigBO.getWorkEmail();
                        if (StrUtil.isNotBlank(workEmail)) {
                            recipientSet.add(workEmail);
                        }
                    }
                }
                noticeConfigVO.setRecipientSet(recipientSet);
                keyMap.put(noticeType, noticeConfigVO);
            }
        }
        Collection<NoticeConfigVO> values = keyMap.values();
        return new ArrayList<>(values);
    }

    @Override
    public List<OptionNode> findCalFields(String eventCode) {
        final SysMessageEvent event = sysMessageEventMapper.selectOne(Wrappers.<SysMessageEvent>lambdaQuery()
                .eq(SysMessageEvent::getEventCode, eventCode));
        final List<SysMessageTypeField> fieldList = messageTypeFieldMapper.selectList(Wrappers.<SysMessageTypeField>lambdaQuery()
                .eq(SysMessageTypeField::getTypeId, event.getTypeId())
                .eq(SysMessageTypeField::getIsCal, true));
        return fieldList.stream().map(it -> new OptionNode(it.getFieldName(), it.getFieldName()))
                .collect(Collectors.toList());
    }

    /**
     * 保存事件规则
     */
    @Override
    public void saveEventRule(SysMessageEventSaveRule saveRule) {
        if (saveRule.getId() != null) {
            //更新
            saveRuleMapper.updateById(saveRule);
        } else {
            saveRuleMapper.insert(saveRule);
        }
        //计算规则
        final String eventCode = saveRule.getEventCode();
        LambdaQueryWrapper<SysMessageEventCalRule> calRuleWrapper = Wrappers.<SysMessageEventCalRule>lambdaQuery().eq(SysMessageEventCalRule::getEventCode, eventCode);
        List<SysMessageEventCalRule> calRuleList = calRuleMapper.selectList(calRuleWrapper);
        if (CollUtil.isNotEmpty(calRuleList)) {
            //删除旧计算规则
            calRuleMapper.delete(calRuleWrapper);
            for (SysMessageEventCalRule it : calRuleList) {
                //删除旧的比较规则
                calCompareMapper.delete(Wrappers.<SysMessageEventCalCompare>lambdaQuery().eq(SysMessageEventCalCompare::getRuleId, it.getId()));
            }
        }
        //保存新的计算规则
        if (CollUtil.isNotEmpty(saveRule.getCalRuleList())) {
            for (SysMessageEventCalRule it : saveRule.getCalRuleList()) {
                it.setEventCode(eventCode);
                calRuleMapper.insert(it);
                for (SysMessageEventCalCompare calCompare : it.getCompareList()) {
                    calCompare.setRuleId(it.getId());
                    calCompareMapper.insert(calCompare);
                }
            }
        }
    }

    /**
     * 查询事件规则
     */
    @Override
    public SysMessageEventSaveRule findEventRuleDetail(String eventCode) {
        //查询保存规则
        SysMessageEventSaveRule saveRule = saveRuleMapper.selectOne(Wrappers.<SysMessageEventSaveRule>lambdaQuery()
                .eq(SysMessageEventSaveRule::getEventCode, eventCode));
        if (saveRule == null) {
            return saveRule;
        }
        //事件信息
        final SysMessageEvent event = sysMessageEventMapper.selectOne(Wrappers.<SysMessageEvent>lambdaQuery()
                .eq(SysMessageEvent::getEventCode, eventCode).eq(SysMessageEvent::getStatus, 1));
        if (event == null) {
            //事件关闭了
            return saveRule;
        }
        saveRule.setTypeId(event.getTypeId());
        //查询计算规则
        List<SysMessageEventCalRule> calRuleList = calRuleMapper.selectList(Wrappers.<SysMessageEventCalRule>lambdaQuery()
                .eq(SysMessageEventCalRule::getEventCode, eventCode));
        if (CollUtil.isNotEmpty(calRuleList)) {
            for (SysMessageEventCalRule it : calRuleList) {
                List<SysMessageEventCalCompare> compareList = calCompareMapper.selectList(Wrappers.<SysMessageEventCalCompare>lambdaQuery()
                        .eq(SysMessageEventCalCompare::getRuleId, it.getId()));
                it.setCompareList(compareList);
            }
        }
        saveRule.setCalRuleList(calRuleList);
        return saveRule;
    }

    @Override
    public List<OptionNode> findEventByTypeId(Integer typeId) {
        final List<SysMessageEvent> eventList = sysMessageEventMapper.selectList(Wrappers.<SysMessageEvent>lambdaQuery()
                .eq(SysMessageEvent::getTypeId, typeId));
        return eventList.stream().map(it -> new OptionNode(it.getEventName(), it.getEventCode())).collect(Collectors.toList());
    }

    @Override
    public List<SysMessageTypeField> findTypeFields(Integer typeId) {
        return messageTypeFieldMapper.selectList(Wrappers.<SysMessageTypeField>lambdaQuery()
                .eq(SysMessageTypeField::getTypeId, typeId));
    }

}
